from lib import *

def safebreak(func):
    def wrapper(*args, **kwargs):
        try : func(*args, **kwargs)
        except Exception as e : print("Break Reason : %s"%e)
        finally : print("\033[0m")
    return wrapper

class Simulation:
    def __init__(self, name, *,debug=False):
        self.chips = {}
        self.monitor = []
        self.maxframe = 0
        self.projectName = name
        self.debug = debug
    def __getitem__(self, key:str):
        return self.chips[key]
    def addChip(self, chipName:str, chip:Chip):
        self.chips[chipName] = chip
        if self.maxframe <= chip.maxframe :
            self.maxframe = chip.maxframe + 1
    def addMonitor(self, chip):
        self.monitor.append(chip)
    @safebreak
    def run(self):
        print(f"\033[2J\033[0;0H{self.projectName}")
        while(True):
            for now in range(self.maxframe):
                if now : toUpdate = list(filter(None, [chip.update(now) for chip in toUpdate]))
                else : toUpdate = list(filter(None, [self.chips[n].update(now) for n in self.chips]))
            print("\033[2J\033[1;0H", end="")
            if not self.debug :
                for n in self.chips:
                    try : 
                        self.chips[n].__show__
                        print(f"[{n}] : ", end="")
                        self.chips[n].__show__()
                    except : pass
            else : 
                for n in self.chips : 
                    if type(self.chips[n]) is LedSet : continue
                    print(f"{n} : pinIN:[{self.chips[n].pinIN}] pinOUT:[{self.chips[n].pinOUT}]")
                    try : print(f"{n} : _dat:[{self.chips[n]._dat}]")
                    except : pass
    @staticmethod
    def bind(FROM, TO, *, mode=0):
        bind(FROM, TO, mode=mode)

